<?php
/**
 * Created by PhpStorm.
 * User: bolle
 * Date: 24.12.15
 * Time: 10:40
 */

namespace tbollmeier\alteraparser\syntaxgraph;

use tbollmeier\alteraparser\io\InputStream;


class MatchFinder implements Processor
{

    private $path;
    private $input;
    private $buffer;
    private $matchChar;
    private $stopped;

    public function __construct(InputStream $input)
    {
        $this->path = [];
        $this->input = $input;
        $this->buffer = [];
        $this->matchChar = null;
        $this->stopped = false;
    }

    public function process(Vertex $vertex, $path)
    {
        if ($this->stopped)
            return ProcessingResult::STOP;

        if (!$this->matchChar)
            $this->matchChar = $this->getNextChar();

        if ($this->matchChar) {
            return $this->processWithCharSearch($vertex);
        } else {
            return $this->processWithoutCharSearch($vertex);
        }

    }

    public function undo(Vertex $vertex, $path)
    {
        if (count($this->path) === 0) return;

        $segment = $this->path[count($this->path)-1];
        $v = $segment[0];
        $ch = $segment[1];

        if ($v === $vertex) {
            array_pop($this->path);
            if ($ch !== null) {
                if ($this->matchChar !== null) {
                    array_push($this->buffer, $this->matchChar);
                    $this->matchChar = null;
                }
                array_push($this->buffer, $ch);
            }
        }

        if ($vertex->isGroupEnd() && $vertex->isEndOfUniqueRule) {
            $this->stopped = true;
        }

    }

    /**
     * @return array
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * @return boolean
     */
    public function isStopped()
    {
        return $this->stopped;
    }

    private function getNextChar()
    {
        if (count($this->buffer) > 0) {
            return array_pop($this->buffer);
        } else {
            if ($this->input->hasNextChar()) {
                return $this->input->getNextChar();
            } else {
                return null;
            }
        }
    }

    private function processWithCharSearch(Vertex $vertex)
    {
        switch ($vertex->getCategory()) {
            case VertexCategory::MATCHER:
                if ($vertex->matches($this->matchChar)) {
                    array_push($this->path, [$vertex, $this->matchChar]);
                    $this->matchChar = null;
                    return ProcessingResult::DO_CONTINUE;
                } else {
                    return ProcessingResult::GO_BACK;
                }
            case VertexCategory::END:
                return ProcessingResult::GO_BACK;
            default:
                array_push($this->path, [$vertex, null]);
                return ProcessingResult::DO_CONTINUE;
        }

    }

    private function processWithoutCharSearch(Vertex $vertex)
    {
        switch ($vertex->getCategory()) {
            case VertexCategory::MATCHER:
                return ProcessingResult::GO_BACK;
            case VertexCategory::END:
                return ProcessingResult::STOP;
            default:
                array_push($this->path, [$vertex, null]);
                return ProcessingResult::DO_CONTINUE;
        }
    }

}